package udp;


import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;

import udp.message.UdpMessage;

/**
 *  Udp Server
 * @author Alex
 *
 */
public abstract class UdpServer extends Thread {
	
	protected int port;
	protected String id;
	protected boolean running = false;
	protected DatagramSocket serverSocket;

	public UdpServer(String id, int port){
		this.port = port;
		this.id = id;
	}
	
	public void setPort(int port){
		this.port = port;
	}
	
	public void setId(String id){
		this.id = id;
	}
	
	protected void startUDPServer(String id, int port){
		this.port = port;
		this.id = id;
		this.start();
	}
	
	protected void startUDPServer(){
		this.start();
	}
	
	protected void stopUDP(){
		running = false;
		serverSocket.close();
		
	}
	
	public abstract void receiveMessage(UdpMessage message);
	
	@Override
	public void run() {
		
		serverSocket = null;
		
		if(id == null || id.isEmpty()){
			print("can't start UDP Server, please set 'id'");
			return;
		}
		
		try {
			serverSocket = new DatagramSocket(port);
			print("[threadId:"+this.getId()+"] listening for UDP messages on port [" + port + "]");
			running = true;
		}
		catch(SocketException ex){
			print("Couldn't create socket: " + ex.getMessage());
			running = false;
		}

		while (running) {
            try {
            	byte[] receive = new byte[2048];
            	DatagramPacket packet =  new DatagramPacket(receive, receive.length );
            	//System.out.println("UdpServer before serverSocket.receive");
                serverSocket.receive(packet);
                //System.out.println("UdpServer after serverSocket.receive");
                UdpMessage udpMessage = (UdpMessage) deserialize(packet);
                udpMessage.setSocketPort(packet.getPort());
                //String hostname = InetAddress.getByAddress(packet.getAddress().getAddress());
                //print("received message from [" + packet.getAddress() + ":" + packet.getPort() +"]");
                receiveMessage(udpMessage);
            }
            catch (Exception e) {
            	//e.printStackTrace();
				print("server socket is not active");
            	//print("there was an exception receiving the message " + e.getMessage());
            	//e.printStackTrace();
            	//System.err.println("[threadId:"+this.getId()+"] error in connection attempt : " + e.getMessage());
            	running = false;
            }
        }
		print("@@@@STOP SERVER@@@@");
		
	}
	
	private Object deserialize(DatagramPacket packet) throws IOException, ClassNotFoundException {
        ByteArrayInputStream byteStream = new ByteArrayInputStream(packet.getData(),packet.getOffset(),packet.getLength());
        ObjectInputStream objectStream = new ObjectInputStream(byteStream);
        return (UdpMessage) objectStream.readObject();
    }
	
	private void print(String msg){
		System.out.println("["+id+"] " + msg);
	}
	
}
